package com.rz.htk.postal.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rz.core.exception.GlobalException;
import com.rz.htk.config.RedisKeyConfig;
import com.rz.htk.postal.entity.ExpressCode;
import com.rz.htk.postal.entity.ExpressCodeRecord;
import com.rz.htk.postal.mapper.ExpressCodeMapper;
import com.rz.htk.postal.service.IExpressCodeRecordService;
import com.rz.htk.postal.service.IExpressCodeService;
import com.rz.htk.product.entity.Product;
import com.rz.htk.product.entity.ProductPrice;
import com.rz.htk.product.service.IProductPriceService;
import com.rz.htk.product.service.IProductService;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Resource;
import java.io.IOException;
import java.text.NumberFormat;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName ExpressCodeServiceImpl
 * @Description 快递单号service
 * @Author maweiyue
 * @Date 2019/3/27 18:42
 */
@Service
public class ExpressCodeServiceImpl extends ServiceImpl<ExpressCodeMapper, ExpressCode> implements IExpressCodeService {

    private static Logger logger = LoggerFactory.getLogger("ExpressCodeServiceImpl");

    @Resource
    RedisTemplate redisTemplate;

    @Resource
    IProductPriceService productPriceService;

    @Resource
    IProductService productService;

    @Resource
    IExpressCodeRecordService expressCodeRecordService;

    @Override
    public IPage<ExpressCode> getPage(ExpressCode expressCode) {
        QueryWrapper<ExpressCode> wrapper = new QueryWrapper();
        if (StringUtils.isNotEmpty(expressCode.getPrdCode())) {
            wrapper.like("prd_code", expressCode.getPrdCode());
        }
        if (StringUtils.isNotEmpty(expressCode.getExpressType())) {
            wrapper.like("express_type", expressCode.getExpressType());
        }
        Page<ExpressCode> page = new Page<>(expressCode.getPageNo(), expressCode.getPageSize());
        IPage<ExpressCode> desktopIPage = page(page, wrapper);
        buildResult(desktopIPage.getRecords());
        return desktopIPage;
    }

    private void buildResult(List<ExpressCode> records) {
        List<String> prdCodeList = new ArrayList<>();
        records.forEach(expressCode->{
            String key = RedisKeyConfig.EXPRESS_CODE_QUEUE + expressCode.getPrdCode() + "_" + expressCode.getExpressType();
            expressCode.setCodeCount(this.redisTemplate.opsForList().size(key));

            prdCodeList.add(expressCode.getPrdCode());
        });
        List<Product> productList = this.productService.listProductByCodes(prdCodeList);
        records.forEach(expressCode -> {
            productList.forEach(product -> {
                if (expressCode.getPrdCode().equals(product.getPrdCode())) {
                    expressCode.setPrdName(product.getPrdName());
                }
            });
        });
    }

    /**
     * 导入快递单号
     * @return
     */
    @Override
    @Transactional
    public boolean importExpressCode(ExpressCode expressCodeParam, MultipartFile file) {
        try {
            Workbook workbook = getWorkbook(file);
            int sheetCounts = workbook.getNumberOfSheets();
            List<String> list = new ArrayList<>();
            NumberFormat nf = NumberFormat.getInstance();
            for (int i = 0; i < sheetCounts; i++) {
                Sheet sheet = workbook.getSheetAt(i);
                int rowCount = sheet.getPhysicalNumberOfRows();
                for (int j = 0; j < rowCount; j++) {
                    Row row = sheet.getRow(j);
                    CellType type = row.getCell(0).getCellTypeEnum();
                    if (CellType.NUMERIC == type) {
                        String expressCode = nf.format(row.getCell(0).getNumericCellValue());
                        if (expressCode.indexOf(",") >= 0) {
                            expressCode = expressCode.replace(",", "");
                        }
                        if (StringUtils.isNotEmpty(expressCode)) {
                            list.add(expressCode);
                        }
                    } else if (CellType.STRING == type) {
                        String expressCode = row.getCell(0).getStringCellValue();
                        if (StringUtils.isNotEmpty(expressCode)) {
                            list.add(expressCode);
                        }
                    }
                }
            }
            ExpressCode expressCode = getExpressCodeEntity(expressCodeParam);
            if (expressCode == null) {
                expressCode = new ExpressCode();
                expressCode.setCrteTime(LocalDateTime.now());
                expressCode.setPrdCode(expressCodeParam.getPrdCode());
                expressCode.setExpressType(expressCodeParam.getExpressType());
            }
            expressCode.setCrteMngId(expressCodeParam.getCrteMngId());
            expressCode.setUpdtMngId(expressCodeParam.getCrteMngId());
            expressCode.setUpdtTime(LocalDateTime.now());
            this.saveOrUpdate(expressCode);

            ExpressCodeRecord expressCodeRecord = new ExpressCodeRecord();
            expressCodeRecord.setExpressCodeId(expressCode.getId());
            expressCodeRecord.setPrdCode(expressCode.getPrdCode());
            expressCodeRecord.setExpressType(expressCode.getExpressType());
            expressCodeRecord.setCrteMngId(expressCodeParam.getCrteMngId());
            expressCodeRecord.setCrteTime(LocalDateTime.now());
            expressCodeRecord.setStartCode(list.get(0));
            expressCodeRecord.setEndCode(list.get(list.size() - 1));
            expressCodeRecord.setCodeCount(list.size());
            expressCodeRecordService.saveOrUpdate(expressCodeRecord);

            String key = RedisKeyConfig.EXPRESS_CODE_QUEUE + expressCodeParam.getPrdCode() + "_" + expressCodeParam.getExpressType();
            redisTemplate.opsForList().leftPushAll(key, list);
            logger.info("导入【" + expressCodeParam.getPrdCode() + "-" + expressCodeParam.getExpressType() + "】快递单号" + list.size() + "条。");
        } catch (Exception ex) {
            throw new GlobalException("文件解析错误！");
        }
        return true;
    }

    private Workbook getWorkbook(MultipartFile file) {
        String fileName = file.getOriginalFilename();
        //创建Workbook工作薄对象，表示整个excel
        Workbook workbook = null;
        try {
            //根据文件后缀名不同(xls和xlsx)获得不同的Workbook实现类对象
            if(fileName.endsWith("xls")){
                //2003
                workbook = new HSSFWorkbook(file.getInputStream());
            }else if(fileName.endsWith("xlsx")){
                //2007
                workbook = new XSSFWorkbook(file.getInputStream());
            }
        } catch (IOException e) {
            logger.info(e.getMessage());
        }
        return workbook;
    }

    public ExpressCode getExpressCodeEntity(ExpressCode expressCodeParam){
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("prd_code", expressCodeParam.getPrdCode());
        queryWrapper.eq("express_type", expressCodeParam.getExpressType());
        List<ExpressCode> list = list(queryWrapper);
        if (CollectionUtils.isNotEmpty(list)) {
            return list.get(0);
        }
        return null;
    }

    /**
     * 获取一个快递单号
     * @param expressCodeParam
     * @return
     */
    @Override
    public String getExpressCode(ExpressCode expressCodeParam){
        String key = RedisKeyConfig.EXPRESS_CODE_QUEUE + expressCodeParam.getPrdCode() + "_" + expressCodeParam.getExpressType();
        Object expressCode = this.redisTemplate.opsForList().rightPop(key);
        if (expressCode == null) {
            throw new GlobalException("快递单号告罄！");
        }
        return expressCode.toString();
    }

    /**
     * 获取一个快递单号
     * @param productPriceId 产品资费信息id（路向id）
     * @return
     */
    @Override
    public String getExpressCode(Integer productPriceId) {
        ProductPrice price = productPriceService.getById(productPriceId);
        if (price != null) {
            ExpressCode expressCodeParam = new ExpressCode();
            expressCodeParam.setExpressType(price.getExpressType());
            expressCodeParam.setPrdCode(price.getPrdCode());
            return getExpressCode(expressCodeParam);
        }
        return null;
    }


    /**
     * 添加一个快递单号
     * @param productPriceId
     * @param expressCode
     * @return
     */
    public void putExpressCode(Integer productPriceId, String expressCode) {
        ProductPrice price = productPriceService.getById(productPriceId);
        if (price != null) {
            String key = RedisKeyConfig.EXPRESS_CODE_QUEUE + price.getPrdCode() + "_" + price.getExpressType();
            redisTemplate.opsForList().leftPush(key, expressCode);
        }
    }


    /**
     * 根据产品获取一个快递单号（默认获取“平邮”产品的快递单号）
     * @param prdCode
     * @return
     */
    public String getExpressCode(String prdCode){
        return getExpressCode(prdCode, "1");
    }

    /**
     * 根据产品和快递类型（平邮/挂号）获取一个快递单号
     * @param prdCode
     * @param expressType
     * @return
     */
    public String getExpressCode(String prdCode, String expressType){
        String key = RedisKeyConfig.EXPRESS_CODE_QUEUE + prdCode + "_" + expressType;
        Object expressCode = this.redisTemplate.opsForList().rightPop(key);
        if (expressCode == null) {
            throw new GlobalException("快递单号告罄！");
        }
        return expressCode.toString();
    }
}
